/*
*   文件数据信息管理模块
*/


#ifndef __BUC_DATAM__
#define __BUC_DATAM__

#include "util.hpp"
#include "config.hpp"
#include <unordered_map>
#include <pthread.h>
#include <mutex>
#include <memory>


namespace cloud
{
    //数据信息结构体
    typedef struct BackUpInfo_t {
        public:
        
        BackUpInfo_t() = default;
        BackUpInfo_t(const std::string& realpath) { InitBackupinfo(realpath); }
        bool pack_flag; //是否压缩标志
        size_t fsize; //文件大小
        time_t atime; //最后一次访问时间
        time_t mtime; //最后一次修改时间
        std::string real_path; //文件实际存储路径名称
        std::string pack_path; //压缩包存储路径名称
        std::string url_path; //请求url

        //指定文件的url获取路径 封装一个BackUpInfo
        void InitBackupinfo(const std::string& realpath)
        {
            FileUtil file(realpath);
            Config* conf = Config::GetInstance();
            pack_flag = 0;
            fsize = file.FileSize();
            atime = file.FileAccTime();
            mtime = file.FileModTime();
            real_path = realpath;
            // 文件路径 + 文件名 + 压缩文件后缀
            pack_path = conf->GetPackDir() + file.FileName() + conf->GetPackfileSuffix();
            url_path = conf->GetDownloadPrefix() + file.FileName();
        }
    }BackupInfo;

    //数据信息管理类
    class DataManager {
        private:
            std::string _backup_file; //持久化存储文件名
            std::unordered_map<std::string,BackupInfo> _table; //内存中以hash表存储
            pthread_rwlock_t _rwlock; // 读写锁--读共享 写互斥
            static std::mutex _mutex;
            static DataManager* _instance;
        private:
            DataManager() //初始化加载，在每次系统重启都要加载以前的数据
            {
                _backup_file = Config::GetInstance()->GetBackUpFile();
                pthread_rwlock_init(&_rwlock,nullptr);
                InitLoad();
            }

        public:
            using ptr = std::shared_ptr<DataManager>;
            static DataManager* GetInstance() 
            {
                if(_instance == nullptr)
                {
                    _mutex.lock();
                    if(_instance == nullptr) _instance = new DataManager();
                    _mutex.unlock();
                }
                return _instance;
            }

            ~DataManager() { pthread_rwlock_destroy(&_rwlock); }

            bool InitLoad()
            {
                FileUtil file(_backup_file);
                if(file.Exists() == false) return true; //如果文件不存在 则不需要加载本地
                //获取文件信息
                std::string jsonstr;
                file.GetContent(&jsonstr);
                if(jsonstr.size() < 3) return true; //没有信息 接下来不需要处理了
                //反序列化
                Json::Value root;
                if(JsonUtil::UnSerialize(jsonstr,&root) == false)
                {
                    std::cout<<"InitLoad(): unserialize error!"<<std::endl;
                    return false;
                }
                int n = root.size();
                for(int i = 0;i<n;++i)
                {
                    BackupInfo info;
                    info.pack_flag = root[i]["pack_flag"].asBool();
                    info.fsize = root[i]["fsize"].asInt64();
                    info.atime = root[i]["atime"].asInt64();
                    info.mtime = root[i]["mtime"].asInt64();
                    info.real_path = root[i]["real_path"].asString();
                    info.pack_path = root[i]["pack_path"].asString();
                    info.url_path = root[i]["url_path"].asString();
                    Insert(info);
                }
                return true;
            }

            bool Storage() //每次数据新增或修改都要重新持久化存储，避免数据丢失
            {
                //获取数据管理信息
                std::vector<BackupInfo> array;
                GetAll(&array);
                //序列化
                Json::Value root;
                for(const auto& info:array)
                {
                    Json::Value val;
                    val["pack_flag"] = info.pack_flag;
                    val["fsize"] = (Json::Int64)info.fsize;
                    val["atime"] = (Json::Int64)info.atime;
                    val["mtime"] = (Json::Int64)info.mtime;
                    val["real_path"] = info.real_path;
                    val["pack_path"] = info.pack_path;
                    val["url_path"] = info.url_path;
                    root.append(val);
                }
                //获取序列化字符串
                std::string jsonstr;
                if(JsonUtil::Serialize(root,&jsonstr) == false)
                {
                    std::cout<<"Storage(): serialize error!"<<std::endl;
                    return false;
                }
                
                //写入到文件
                FileUtil file(_backup_file);
                if(file.SetTruncContent(jsonstr) == false)
                {
                    std::cout<<"Storage(): set trunc content error!"<<std::endl;
                    return false;
                }

                return true;
            }

            bool Insert(const BackupInfo& info) //新增
            {
                pthread_rwlock_wrlock(&_rwlock); //上锁
                bool ok =_table.emplace(info.url_path,info).second; //如果已存在则插入不成功
                pthread_rwlock_unlock(&_rwlock); //解锁
                Storage(); //每次修改都刷新
                return ok;
            }
            bool Update(const BackupInfo& info) //修改
            {
                pthread_rwlock_wrlock(&_rwlock); //上锁
                if(_table.count(info.url_path) == 0) return false; //如果不存在则不刷新
                _table[info.url_path] = info;
                pthread_rwlock_unlock(&_rwlock); //解锁
                Storage(); //每次修改都刷新
                return false;
            }
            bool IsExists(const BackupInfo& info) { return _table.count(info.url_path) == 1; }
            bool GetOneByUrl(const std::string& url,BackupInfo* info) //通过url获取对应文件的数据信息
            {
                bool ret = false;
                pthread_rwlock_wrlock(&_rwlock); //上锁
                auto it = _table.find(url);
                if(it != _table.end()) 
                {
                    *info = it->second;
                    ret = true;
                }
                pthread_rwlock_unlock(&_rwlock); //解锁
                return ret;
            }
            bool GetOneByRealpath(const std::string& realpath,BackupInfo* info) //通过文件实际存储路径获取文件的数据信息(用于服务器内部文件和热点管理)
            {
                bool ret = false;
                pthread_rwlock_wrlock(&_rwlock); //上锁
                auto it = _table.begin();
                while(it != _table.end()) 
                {
                    if(it->second.real_path == realpath)
                    {
                        *info = it->second;
                        ret = true;
                        break;
                    }
                    ++it;
                }
                pthread_rwlock_unlock(&_rwlock); //解锁
                return ret;
            }
            void GetAll(std::vector<BackupInfo>* array) //获取所有文件的文件信息
            {
                pthread_rwlock_wrlock(&_rwlock); //上锁
                for(const auto& node:_table) array->push_back(node.second);
                pthread_rwlock_unlock(&_rwlock); //解锁
            }
            
    };
    std::mutex DataManager::_mutex;
    DataManager* DataManager::_instance = nullptr;
}

#endif
